﻿using System.Collections.Generic;
using System.Linq;

namespace RNA_Libraries
{
  public class Vertex : Sequence
  {
    #region Public Interface

    public Vertex(Sequence s) : base(s) { }

    public Vertex(string data) : base(data) { }

    public void AddEdge(Edge edge)
    {
      if (edge.Start == this)
      {
        if (edge.L > m_maxL)
        {
          m_maxL = edge.L;
        }
        m_adjacent.Add(edge);
        if (ToString().Contains(edge.End.ToString()))
        {
          m_subSeqs.Add(edge.End);
        }
        //m_surrounding.Add(edge.End);
      }
    }

    public void AddInvEdge(Edge edge)
    {
      if (edge.End == this)
      {
        if (edge.L > m_maxInvL)
        {
          m_maxInvL = edge.L;
        }
        m_adjacentInv.Add(edge);
        if (ToString().Contains(edge.Start.ToString()))
        {
          m_subSeqs.Add(edge.Start);
        }
        //m_surrounding.Add(edge.End);
      }
    }

    public Vertex TruncateToRefSeq(Sequence refSeq)
    {
      int start = 0;
      int end = 0;
      int l = SequenceProcessing.LevenshteinDistance(this, refSeq);
      while (true)
      {
        var ll = SequenceProcessing.LevenshteinDistance(FinishSubstring(Length - start - 1), refSeq.ToString());
        if (ll<l)
        {
          l = ll;
          start++;
        }
        else
        {
          break;
        }
      }
      var str = FinishSubstring(Length - start);
      l = SequenceProcessing.LevenshteinDistance(str, refSeq.ToString());
      while (true)
      {
        var ll = SequenceProcessing.LevenshteinDistance(str.Substring(0, str.Length - end - 1), refSeq.ToString());
        if (ll<l)
        {
          l = ll;
          end++;
        }
        else
        {
          break;
        }
      }
      var res = str.Substring(0, str.Length - end);
      return new Vertex(res);
    }

    public void ProcessVertex()
    {
      if (m_maxL == -1) m_adjacent.Clear();
      else m_adjacent = new List<Edge>(m_adjacent.Where(e => e.L == m_maxL));
      if (m_maxInvL == -1) m_adjacentInv.Clear();
      else m_adjacentInv = new List<Edge>(m_adjacentInv.Where(e => e.L == m_maxInvL));
      //m_surrounding = new List<Vertex>(m_adjacent.Select(e => e.End));
    }

    #endregion

    #region Public Properties

    public int Number;

    public List<Edge> Adjacent { get { return m_adjacent; } }
    public List<Edge> AdjacentInv { get { return m_adjacentInv; } }
    public List<Vertex> SubVers { get { return m_subVertexes; } }

    #endregion

    #region Private Fields

    private List<Edge> m_adjacent = new List<Edge>(10);
    private List<Edge> m_adjacentInv = new List<Edge>(10);
    private readonly List<Vertex> m_subVertexes = new List<Vertex>(10);
    private int m_maxL = -1;
    private int m_maxInvL = -1;
    private List<Vertex> m_subSeqs = new List<Vertex>(10);

    #endregion

    #region Overrides

    public override bool Equals(object obj)
    {
      if (ReferenceEquals(null, obj)) return false;
      if (ReferenceEquals(this, obj)) return true;
      return Equals(obj as Vertex);
    }

    public bool Equals(Vertex other)
    {
      return base.Equals(other);
    }

    public override int GetHashCode()
    {
      return base.GetHashCode();
    }

    public static bool operator ==(Vertex left, Vertex right)
    {
      return Equals(left, right);
    }

    public static bool operator !=(Vertex left, Vertex right)
    {
      return !Equals(left, right);
    }

    #endregion
  }
}
